package com.inifitness.tenant.core.config.excel;

import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import com.alibaba.excel.context.AnalysisContext;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.inifitness.common.basic.BaseEnum;
import com.inifitness.common.constants.SystemConstants;
import com.inifitness.common.easyexcel.MyAnalysisEventListener;
import com.inifitness.common.enums.GenderEnum;
import com.inifitness.common.enums.StatusEnum;
import com.inifitness.tenant.core.system.converter.BizUserAcctConverter;
import com.inifitness.tenant.core.system.model.entity.BizRole;
import com.inifitness.tenant.core.system.model.entity.BizUserAcct;
import com.inifitness.tenant.core.system.model.entity.BizUserAcctRole;
import com.inifitness.tenant.core.system.model.vo.BizUserAcctImportVO;
import com.inifitness.tenant.core.system.service.BizRoleService;
import com.inifitness.tenant.core.system.service.BizUserAcctRoleService;
import com.inifitness.tenant.core.system.service.BizUserAcctService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.log4j.Log4j2;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;

/**
 * 用户导入监听器
 * <p>
 * <a
 * href="https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read#%E6%9C%80%E7%AE%80%E5%8D%95%E7%9A%84%E8%AF%BB%E7%9A%84%E7%9B%91%E5%90%AC%E5%99%A8">最简单的读的监听器</a>
 *
 * @author sunjinfeng
 * @since 2024/04/18 11:00:00
 */
@Log4j2
public class UserAcctImportListener extends MyAnalysisEventListener<BizUserAcctImportVO> {

  /**
   * 有效条数
   */
  private int validCount;

  /**
   * 无效条数
   */
  private int invalidCount;

  private final String filename;

  /**
   * 部门ID
   */
  private final Long deptId;

  private final BizUserAcctService userService;

  private final PasswordEncoder passwordEncoder;

  private final BizUserAcctConverter bizUserAcctConverter;

  private final BizRoleService roleService;

  private final BizUserAcctRoleService userRoleService;

  public UserAcctImportListener(Long deptId) {
    this.deptId = deptId;
    this.filename = UUID.randomUUID().toString();
    this.userService = SpringUtil.getBean(BizUserAcctService.class);
    this.passwordEncoder = SpringUtil.getBean(PasswordEncoder.class);
    this.roleService = SpringUtil.getBean(BizRoleService.class);
    this.userRoleService = SpringUtil.getBean(BizUserAcctRoleService.class);
    this.bizUserAcctConverter = SpringUtil.getBean(BizUserAcctConverter.class);
  }

  /**
   * 每一条数据解析都会来调用.
   * <p>
   * 1. 数据校验；全字段校验 2. 数据持久化；
   *
   * @param bizUserAcctImportVO 一行数据，类似于 {@link AnalysisContext#readRowHolder()}
   * @param analysisContext     分析上下文
   */
  @Override
  public void invoke(BizUserAcctImportVO bizUserAcctImportVO, AnalysisContext analysisContext) {
    log.info(()-> MessageFormatter.format("解析到一条用户数据:{}", JSONUtil.toJsonStr(bizUserAcctImportVO)));
    // 校验数据
    StringBuilder validationMsg = new StringBuilder();

    String username = bizUserAcctImportVO.getUsername();
    if (CharSequenceUtil.isBlank(username)) {
      validationMsg.append("用户名为空；");
    } else {
      long count = userService.count(
          new LambdaQueryWrapper<BizUserAcct>().eq(BizUserAcct::getUsername, username));
      if (count > 0) {
        validationMsg.append("用户名已存在；");
      }
    }

    String nickname = bizUserAcctImportVO.getNickname();
    if (CharSequenceUtil.isBlank(nickname)) {
      validationMsg.append("用户昵称为空；");
    }

    String mobile = bizUserAcctImportVO.getMobile();
    if (CharSequenceUtil.isBlank(mobile)) {
      validationMsg.append("手机号码为空；");
    } else {
      if (!Validator.isMobile(mobile)) {
        validationMsg.append("手机号码不正确；");
      }
    }

    if (validationMsg.isEmpty()) {
      // 校验通过，持久化至数据库
      BizUserAcct entity = bizUserAcctConverter.importVo2Entity(bizUserAcctImportVO);
      entity.setDeptId(deptId);
      entity.setPassword(passwordEncoder.encode(SystemConstants.DEFAULT_PASSWORD));
      // 性别翻译
      String genderLabel = bizUserAcctImportVO.getGenderLabel();
      if (CharSequenceUtil.isNotBlank(genderLabel)) {
        Integer genderValue = (Integer) BaseEnum.getValueByLabel(genderLabel, GenderEnum.class);
        entity.setGender(genderValue);
      }

      // 角色解析
      String roleCodesString = bizUserAcctImportVO.getRoleCodes();
      List<Long> roleIds = null;
      String[] roleCodes = StringUtils.split(",",roleCodesString);
      if (ArrayUtil.isNotEmpty(roleCodes)) {
        roleIds = roleService.list(
                new LambdaQueryWrapper<BizRole>()
                    .in(BizRole::getCode, Arrays.asList(roleCodes))
                    .eq(BizRole::getStatus, StatusEnum.ENABLE.getValue())
                    .select(BizRole::getId)
            ).stream()
            .map(BizRole::getId)
            .toList();
      }

      boolean saveResult = userService.save(entity);
      if (saveResult) {
        validCount++;
        // 保存用户角色关联
        if (CollUtil.isNotEmpty(roleIds)) {
          List<BizUserAcctRole> userRoles = roleIds.stream()
              .map(roleId -> new BizUserAcctRole(entity.getId(), roleId))
              .toList();
          userRoleService.saveBatch(userRoles);
        }
      } else {
        invalidCount++;
        writeToReport("第"+(validCount + invalidCount)+"行数据保存失败；");
      }
    } else {
      invalidCount++;
      writeToReport("第"+(validCount + invalidCount)+"行数据校验失败:"+validationMsg);
    }
  }


  /**
   * 所有数据解析完成会来调用
   *
   * @param analysisContext 解析上下文
   */
  @Override
  public void doAfterAllAnalysed(AnalysisContext analysisContext) {
    log.debug("数据解析完成");
  }


  @Override
  public String getMsg() {
    // 总结信息
    return CharSequenceUtil.format("导入用户结束：成功{}条，失败{}条；<br/>{}", validCount,
        invalidCount);
  }

  public void writeToReport(String line){
    FileUtil.appendString(line, FileUtil.file("/app/import/report/", LocalDate.now().format(
        DateTimeFormatter.ofPattern("yyyyMMdd")),filename,".txt"), StandardCharsets.UTF_8);
  }
}
